package com.example.androidui.view;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Resources;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;

import java.util.ArrayList;
import java.util.List;

/**
 * @ClassName: FlowLayout$
 * @Description: 自定义流式布局
 * @Author: xinya --> mhzhuxinya@163.com
 * @CreateDate: 2020/9/27$ 17:38$
 * @UpdateUser: xinya --> mhzhuxinya@163.com
 * @UpdateDate: 2020/9/27$ 17:38$
 * @UpdateRemark: 更新内容
 *  1.0: 创建自定义流式布局
 * @Version: 1.0
 */
public class FlowLayout extends ViewGroup {
    private static final String TAG = "FlowLayout";
    private int mHorizontalSpacing = dp2px(16); //每个item横向间距
    private int mVerticalSpacing = dp2px(8); //每个item横向间距
    private List<List<View>> mAllLinesView;

    public FlowLayout(Context context) {
        this(context, null);
    }

    public FlowLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        // 保存所有的View
        mAllLinesView = new ArrayList<>();
    }

    // onMeasure 的思路:遍历所有的子View,计算出子View所需要的高度与最大宽度,然后在判断自身mode,计算出来宽高
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        Log.d(TAG, "onMeasure: ");
        // 清空 mAllLinesView，防止多次onMeasure多次添加view的问题,参考 FrameLayout中的onMeasure,里面调用了2次
        clearAllChileViews();
        // 获取自定义ViewGroup的mode/size/padding
        int containerWidthMode = MeasureSpec.getMode(widthMeasureSpec);
        int containerWidthSize = MeasureSpec.getSize(widthMeasureSpec);
        int containerHeightMode = MeasureSpec.getMode(heightMeasureSpec);
        int containerHeightSize = MeasureSpec.getSize(heightMeasureSpec);
        int containerPaddingLeft = getPaddingLeft();
        int containerPaddingTop = getPaddingTop();
        int containerPaddingRight = getPaddingRight();
        int containerPaddingBottom = getPaddingBottom();
        // 获取自定义ViewGroup的子View数量
        int childCount = getChildCount();

        // 保存一行的View
        @SuppressLint("DrawAllocation") List<View> lineViews = new ArrayList<>();
        // 记录一行view已使用的宽度
        int lineWidthUsed = 0;

        for (int index = 0; index < childCount; index++) {
            View childView = getChildAt(index);
            if (childView.getVisibility() == GONE) continue;
            LayoutParams childViewLayoutParams = childView.getLayoutParams();
            int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
                    containerPaddingLeft + containerPaddingRight,
                    childViewLayoutParams.width);
            int childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec,
                    containerPaddingTop + containerPaddingBottom,
                    childViewLayoutParams.height);
            // 子View测量
            childView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
            // 获取测量后的子View的宽高
            int childWidth = childView.getMeasuredWidth();
            if (childWidth + lineWidthUsed + mHorizontalSpacing > containerWidthSize) {
                mAllLinesView.add(lineViews);

                lineWidthUsed = 0;
                lineViews = new ArrayList<>();
            }

            lineViews.add(childView);
            lineWidthUsed += childWidth + mHorizontalSpacing;

            // 处理最后一行的问题
            if (index == childCount - 1) {
                mAllLinesView.add(lineViews);
            }
        }

        // 计算所需要的最大宽度与高度
        int parentNeedWidth = 0;
        int parentNeedHeight = 0;
        for (List<View> views : mAllLinesView) {
            int maxHeight = 0;
            int maxWidth = 0;
            for (View view : views) {
                maxHeight = Math.max(view.getMeasuredHeight(), maxHeight);
                maxWidth += view.getMeasuredWidth() + mHorizontalSpacing;
            }
            parentNeedWidth = Math.max(parentNeedWidth, maxWidth);
            parentNeedHeight += maxHeight + mVerticalSpacing;
        }

        // 判断viewGroup的mode 确认size
        setMeasuredDimension(
                (containerWidthMode == MeasureSpec.EXACTLY) ? containerWidthSize : parentNeedWidth,
                (containerHeightMode == MeasureSpec.EXACTLY) ? containerHeightSize : parentNeedHeight);
    }

    // onLayout 思路:遍历所有的view,计算出来相对值, 然后调用子View layout进行布局
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        Log.d(TAG, "onLayout: ");
        // 获取viewgroup的padding值
        int containerPaddingLeft = getPaddingLeft();
        int childTopMargin = getPaddingTop();

        for (List<View> views : mAllLinesView) {
            int childLeftMargin = containerPaddingLeft;
            int lineMaxHeight = 0;

            for (View view : views) {
                // 计算子view的上下左右边界
                // TODO: 2020/9/27 此处没有考虑gravity的问题
                int childRight = childLeftMargin + view.getMeasuredWidth();
                int childBottom = childTopMargin + view.getMeasuredHeight();
                view.layout(childLeftMargin, childTopMargin, childRight, childBottom);
                childLeftMargin = childRight + mHorizontalSpacing;
                lineMaxHeight = Math.max(lineMaxHeight, view.getMeasuredHeight());

            }
            childTopMargin += lineMaxHeight + mVerticalSpacing;
        }
    }

    /**
     * 清除添加的所有子view
     */
    private void clearAllChileViews() {
        mAllLinesView.clear();
    }

    /**
     * dp转px
     * @param dp
     * @return
     */
    private int dp2px(int dp) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp,
                Resources.getSystem().getDisplayMetrics());
    }
}
